在前兩個章節當中,我們可以看到 MongoDB 對於資料並沒有特別去做什麼規範,基本上是給什麼寫什麼,可想而知如果沒有一個既定的格式的話,資料操作起來會相當不容易,今天我們會介紹 Pydantic 這個套件,他主要是用來建立資料模型,並且提供資料驗證的方式
今天我們主要介紹的內容如下:
明天我們會教學如何將 Pydantic 實際與 MongoDB 的資料進行結合
要透過 Pydantic 建立資模型,我們只需要 import 該套件下的 BaseModel 類別即可,下方為一個簡易的範例
可以看到範例當中,使用 type hint 的方式進行資料的型態驗證,並且可以透過設定 Optional 來指定某個欄位是否需要,若沒有輸入則預設為None,同時我們也可以給予某個欄位預設值,當沒有輸入該欄位時,Pydantic 會自動代入預設值給該欄位
from typing import Optional
from datetime import datetime
from pydantic import BaseModel
class UserModel(BaseModel):
name: str
birthday: datetime
email: Optional[str]
created_time: datetime = datetime.now()
下方為實際利用此模型實體化幾個物件,總共有以下三種情況:
from typing import Optional
from datetime import datetime
from pydantic import BaseModel
class UserModel(BaseModel):
name: str
birthday: datetime
email: Optional[str]
created_time: datetime = datetime.now()
# 正常寫入資料
user = UserModel(
name="nick",
birthday=datetime.now(),
email="nickchen1998@gmail.com"
)
print("------正常寫入資料------")
print(user)
# 缺少 Optional
user = UserModel(
name="nick",
birthday=datetime.now()
)
print("------缺少 Optional------")
print(user)
print("------缺少非 Optional------")
try:
user = UserModel(
birthday=datetime.now(),
email="nickchen1998@gmail.com"
)
except Exception as ex:
print(ex.__class__.__name__)
下方圖片中可以看到三種結果:
我們可以透過 import Pydantic 套件底下的 validator 來進行資料驗證,下方程式碼範例當中,我們透過裝飾器的方式來標註我們要驗證的欄位名稱並建立一個 function 來進行驗證
注意:手動引發的錯誤類別必須為 ValueError,放入其他種類的錯誤似乎會失效
from typing import Optional
from datetime import datetime
from pydantic import BaseModel, validator, ValidationError
class UserModel(BaseModel):
name: str
birthday: datetime
email: Optional[str]
created_time: datetime = datetime.now()
@validator("birthday")
def over_18(cls, birthday: datetime):
if datetime.now().year - birthday.year < 18:
raise ValueError("年紀必須大於 18 歲")
return birthday
print("----大於 18 歲----")
user = UserModel(
name="nick", birthday=datetime(year=1999, month=1, day=1)
)
print(user)
print("----小於 18 歲----")
try:
user = UserModel(
name="nick", birthday=datetime(year=2023, month=1, day=1)
)
print(user)
except ValidationError as ex:
print(ex)
可以看到下圖當中第一次有成功輸出完整的 user 模型,第二次則成功的印出驗證錯誤的錯誤訊息
Enum 時常會做為列舉常數使用,比如 Log 的錯誤等級、任務狀態等等,下方為常見的 Log 錯誤等級的 Enum 範例
from enum import Enum
class LogLevel(Enum):
DEBUG = "debug"
INFO = "info"
WARNING = "warning"
ERROR = "error"
CRITICAL = "critical"
下方的範例中我們可以看到我們在 model 裡面使用了 LogLevel 這個 Enum 並且增加了 Config 這個類別,其中也把 use_enum_values
這欄位設為 True,這將會在我們將模型轉換為 dictionary 的時候自動將 Enum 型別的欄位轉為字串
更多 Config 設定可以參考 這個網址
注意:由於 use_enum_values 會自動協助將 Enum 轉換為 string,因此判斷相等時需要透過取得 Enum 底下的 value 屬性來做判斷
from enum import Enum
from pydantic import BaseModel
class LogLevel(Enum):
DEBUG = "debug"
INFO = "info"
WARNING = "warning"
ERROR = "error"
CRITICAL = "critical"
class LogModel(BaseModel):
level: LogLevel
message: str
class Config:
use_enum_values = True
log_list = [
LogModel(level=LogLevel.DEBUG, message="This is debug level log."),
LogModel(level=LogLevel.INFO, message="This is info level log.")
]
for log in log_list:
if log.level == LogLevel.INFO.value:
print(log.message)
下圖中我們可以看到比對到 info 等級的 log 的時候成功將其 message 印出
我們可以透過呼叫 BaseModel 下的 dict() 方法來將 model 轉換為 dictionary,轉換後我們就可以將該資料直接寫進 MongoDB 當中,下方為簡易的範例
from enum import Enum
from pydantic import BaseModel
class LogLevel(Enum):
DEBUG = "debug"
INFO = "info"
WARNING = "warning"
ERROR = "error"
CRITICAL = "critical"
class LogModel(BaseModel):
level: LogLevel
message: str
class Config:
use_enum_values = True
log = LogModel(level=LogLevel.WARNING, message="This is warning log.")
print(log.dict())
下圖中可以看到我們印出的資料已經成功轉換為 dictionary,且由於有設定 use_enum_values = True
,和 enum 有關的欄位也自動被轉換為字串